package com.atguigu.dga.assess.service.impl;

import com.atguigu.dga.assess.assess.AssessorOld;
import com.atguigu.dga.assess.assess.AssessorTemplate;
import com.atguigu.dga.assess.bean.AssessParam;
import com.atguigu.dga.assess.bean.GovernanceAssessDetail;
import com.atguigu.dga.assess.bean.GovernanceMetric;
import com.atguigu.dga.assess.mapper.GovernanceAssessDetailMapper;
import com.atguigu.dga.assess.service.GovernanceAssessDetailService;
import com.atguigu.dga.assess.service.GovernanceMetricService;
import com.atguigu.dga.config.MetaDataUtil;
import com.atguigu.dga.ds.bean.TDsTaskDefinition;
import com.atguigu.dga.ds.service.TDsTaskDefinitionService;
import com.atguigu.dga.meta.bean.TableMetaInfo;
import com.atguigu.dga.meta.service.TableMetaInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 * 治理考评结果明细 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2023-06-05
 */
@Service
public class GovernanceAssessDetailServiceImpl extends ServiceImpl<GovernanceAssessDetailMapper, GovernanceAssessDetail> implements GovernanceAssessDetailService {

    /*
            1.考生进场
                    考生: 库下的所有表
            2.出题考试
                    题： 考评指标。
                         governance_metric 下，一共18个
            3.收卷，密封，押运
                    把考评的结果GovernanceAssessDetail收集起来。
                        List<GovernanceAssessDetail>

                     保存到数据库。
     */
    @Autowired
    private TableMetaInfoService tableMetaInfoService;

    @Autowired
    private GovernanceMetricService metricService;

    @Autowired
    private AssessorOld assessor;

    @Autowired
    private ApplicationContext context;

    @Autowired
    private MetaDataUtil metaDataUtil;

    @Autowired
    private TDsTaskDefinitionService definitionService;

    @Autowired
    private ThreadPoolTaskExecutor executor;
    @Override
    public void assess(String assessDate) {

        //先删除当前日期已经考评过的结果
        remove(new QueryWrapper<GovernanceAssessDetail>().eq("assess_date",assessDate));

        List<GovernanceAssessDetail> result = new ArrayList<>();
        /*
            1.考生进场 查询所有表的元数据信息
             从数据库的  table_meta_info_extra 和 table_meta_info 查询信息，封装为TableMetaInfo(内置了属性 TableMetaInfoExtra)

             方式一:  参考  TableMetaInfoController.queryTableMetaInfo
                            先查询 table_meta_info，遍历，对于每一个 TableMetaInfo，
                            根据table_name,schema_name查询 table_meta_info_extra，
                            set到 TableMetaInfo对象中。

                            编码成本低。 请求次数多，71次。

            方法二：  一次性查询。 一条sql查两张表，必须得join。只能自己实现，不能用MybatisPlus
                            编码成本高。 请求次数低， 1次。 选择。

         */
        List<TableMetaInfo> tableMetaInfos = tableMetaInfoService.queryAllTableMeta();

        //1.5 添加处理，把查询到的元数据信息，转换为Map : key是表名，value是TableMetaInfo
        if (metaDataUtil.tableMetaInfoMap == null){
            metaDataUtil.tableMetaInfoMap = new HashMap<>();
            for (TableMetaInfo tableMetaInfo : tableMetaInfos) {
                String key = tableMetaInfo.getSchemaName() + "." + tableMetaInfo.getTableName();
                metaDataUtil.tableMetaInfoMap.put(key,tableMetaInfo);
            }
        }

        //为所有的表，都一次性查询到他们的任务定义
        List<TDsTaskDefinition> allTasks = definitionService.getAllTasks(assessDate, metaDataUtil.tableMetaInfoMap.keySet());
        if (metaDataUtil.taskDefinitionMap == null){
            metaDataUtil.taskDefinitionMap = new HashMap<>();
            for (TDsTaskDefinition taskDefinition : allTasks) {
                String key = taskDefinition.getName();
                metaDataUtil.taskDefinitionMap.put(key,taskDefinition);
            }
        }


        /*
             2.出题考试
                    题： 考评指标。
                         governance_metric 下，一共18个
         */
        //查询所有的考试题
        List<GovernanceMetric> metrics = metricService.list(new QueryWrapper<GovernanceMetric>().eq("is_disabled", '否'));

        /*
            考试
                遍历所有的考生(表)，让每个考生遍历所有的题(指标)
                for( for()  )


         */
        //创建期货列表
        CompletableFuture<List<GovernanceAssessDetail>>[] futures = new  CompletableFuture[tableMetaInfos.size()];

        for (int i = 0; i < tableMetaInfos.size(); i++) {
            TableMetaInfo tableMetaInfo = tableMetaInfos.get(i);

            //开启一个线程去考评
            futures[i] = CompletableFuture.supplyAsync(new Supplier<List<GovernanceAssessDetail>>()
            {
                @Override
                public List<GovernanceAssessDetail> get() {
                    return assessProcess(tableMetaInfo,assessDate,metrics);
                }
            },executor);
        }

        //等73张表的每一个线程都运行结束
        CompletableFuture.allOf(futures).join();


           /* 获取结果

            [ {d1,d2,d3},{d4,d5,d6}....  ]
              扁平化 flatMap
            [d1,d2,d3,d4,d5,d6]*/

        List<GovernanceAssessDetail> details = Arrays.stream(futures)
                // flatMap 返回值必须是stream
                .flatMap(future -> future.join().stream())
                .collect(Collectors.toList());

       /* for (TableMetaInfo tableMetaInfo : tableMetaInfos) {


                //每一张表都可以开启一个线程，可以让73张表同时考评


            for (GovernanceMetric metric : metrics) {


                   *//* 判断当前考评的指标是什么，是什么就调用什么方法来处理
                    能解决，但是不利于维护。
                        违反了一个原则:  开闭原则。

                        开闭原则：  开的意思，增加新功能时，应该做到不去修改现有的功能。
                        开闭原则：  闭的意思，减少旧功能时，应该做到不去修改现有的功能。
                        低耦合，高内聚。

                     模版模式。
                            把做事的一般步骤，抽象为一个模版，定义在一个抽象类中。
                            具体做什么事，由子类实现抽象类。
                                如果子类1，不在使用，只需要删除子类1.
                                如果子类2，需要使用，只需要创建子类2。即可。
                                符合开闭原则。

                if ("HAVE_TEC_OWNER".equals(metric.getMetricCode())){
                    assessor.assessHadTecOwnner();
                }else if ("HAVE_BUS_OWNER".equals(metric.getMetricCode())){
                    assessor.assessHadBusiOwnner();
                }else if ("ABC".equals(metric.getMetricCode())){
                    assessor.assessHadBusiOwnner();
                }*//*
                //..... 18层

                //获取指标对应的考评对象
                try {
                    //封装考评参数
                    AssessParam assessParam = new AssessParam(tableMetaInfo, assessDate, metric);
                    AssessorTemplate template = context.getBean(metric.getMetricCode(), AssessorTemplate.class);
                    GovernanceAssessDetail detail = template.doAssess(assessParam);
                    result.add(detail);

                }catch (Exception e){
                    e.printStackTrace();
                    throw new RuntimeException(e);

                }


            }
        }*/

        // 3.收卷，密封，押运
        saveBatch(details);
        // saveBatch(result);

    }

    //封装一个方法，执行考评
    private List<GovernanceAssessDetail> assessProcess(TableMetaInfo tableMetaInfo,String assessDate, List<GovernanceMetric> metrics){
        List<GovernanceAssessDetail> result = new ArrayList<>();

        for (GovernanceMetric metric : metrics) {
            //封装考评参数
            AssessParam assessParam = new AssessParam(tableMetaInfo, assessDate, metric);
            AssessorTemplate template = context.getBean(metric.getMetricCode(), AssessorTemplate.class);
            GovernanceAssessDetail detail = template.doAssess(assessParam);
            result.add(detail);
        }

        return result;
    }
}














